/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifndef vm_Interpreter_inl_h#define vm_Interpreter_inl_h#include"vm/Interpreter.h"#include"jscompartment.h"#include"jsnum.h"#include"jsstr.h"#include"jit/Ion.h"#include"vm/ArgumentsObject.h"#include"jsatominlines.h"#include"jsobjinlines.h"#include"vm/EnvironmentObject-inl.h"#include"vm/Stack-inl.h"#include"vm/String-inl.h"#include"vm/UnboxedObject-inl.h"namespacejs{/* * Every possible consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) (as determined * by ScriptAnalysis::needsArgsObj) must check for these magic values and, when * one is received, act as if the value were the function's ArgumentsObject. * Additionally, it is possible that, after 'arguments' was copied into a * temporary, the arguments object has been created a some other failed guard * that called JSScript::argumentsOptimizationFailed. In this case, it is * always valid (and necessary) to replace JS_OPTIMIZED_ARGUMENTS with the real * arguments object. */staticinlineboolIsOptimizedArguments(AbstractFramePtrframe,MutableHandleValuevp){if(vp.isMagic(JS_OPTIMIZED_ARGUMENTS)&&frame.script()->needsArgsObj())vp.setObject(frame.argsObj());returnvp.isMagic(JS_OPTIMIZED_ARGUMENTS);}/* * One optimized consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) is f.apply. * However, this speculation must be guarded before calling 'apply' in case it * is not the builtin Function.prototype.apply. */staticinlineboolGuardFunApplyArgumentsOptimization(JSContext*cx,AbstractFramePtrframe,CallArgs&args){if(args.length()==2&&IsOptimizedArguments(frame,args[1])){if(!IsNativeFunction(args.calleev(),js::fun_apply)){RootedScriptscript(cx,frame.script());if(!JSScript::argumentsOptimizationFailed(cx,script))returnfalse;args[1].setObject(frame.argsObj());}}returntrue;}/* * Per ES6, lexical declarations may not be accessed in any fashion until they * are initialized (i.e., until the actual declaring statement is * executed). The various LEXICAL opcodes need to check if the slot is an * uninitialized let declaration, represented by the magic value * JS_UNINITIALIZED_LEXICAL. */staticinlineboolIsUninitializedLexical(constValue&val){// Use whyMagic here because JS_OPTIMIZED_ARGUMENTS could flow into here.returnval.isMagic()&&val.whyMagic()==JS_UNINITIALIZED_LEXICAL;}staticinlineboolIsUninitializedLexicalSlot(HandleObjectobj,Handle<PropertyResult>prop){MOZ_ASSERT(prop);if(obj->is<WithEnvironmentObject>())returnfalse;// Proxy hooks may return a non-native property.if(prop.isNonNativeProperty())returnfalse;Shape*shape=prop.shape();if(!shape->hasSlot()||!shape->hasDefaultGetter()||!shape->hasDefaultSetter()){returnfalse;}MOZ_ASSERT(obj->as<NativeObject>().containsPure(shape));returnIsUninitializedLexical(obj->as<NativeObject>().getSlot(shape->slot()));}staticinlinevoidReportUninitializedLexical(JSContext*cx,HandlePropertyNamename){ReportRuntimeLexicalError(cx,JSMSG_UNINITIALIZED_LEXICAL,name);}staticinlinevoidReportUninitializedLexical(JSContext*cx,HandleScriptscript,jsbytecode*pc){ReportRuntimeLexicalError(cx,JSMSG_UNINITIALIZED_LEXICAL,script,pc);}staticinlineboolCheckUninitializedLexical(JSContext*cx,PropertyName*name_,HandleValueval){if(IsUninitializedLexical(val)){RootedPropertyNamename(cx,name_);ReportUninitializedLexical(cx,name);returnfalse;}returntrue;}staticinlineboolCheckUninitializedLexical(JSContext*cx,HandleScriptscript,jsbytecode*pc,HandleValueval){if(IsUninitializedLexical(val)){ReportUninitializedLexical(cx,script,pc);returnfalse;}returntrue;}staticinlinevoidReportRuntimeConstAssignment(JSContext*cx,HandlePropertyNamename){ReportRuntimeLexicalError(cx,JSMSG_BAD_CONST_ASSIGN,name);}staticinlinevoidReportRuntimeConstAssignment(JSContext*cx,HandleScriptscript,jsbytecode*pc){ReportRuntimeLexicalError(cx,JSMSG_BAD_CONST_ASSIGN,script,pc);}inlineboolGetLengthProperty(constValue&lval,MutableHandleValuevp){/* Optimize length accesses on strings, arrays, and arguments. */if(lval.isString()){vp.setInt32(lval.toString()->length());returntrue;}if(lval.isObject()){JSObject*obj=&lval.toObject();if(obj->is<ArrayObject>()){vp.setNumber(obj->as<ArrayObject>().length());returntrue;}if(obj->is<ArgumentsObject>()){ArgumentsObject*argsobj=&obj->as<ArgumentsObject>();if(!argsobj->hasOverriddenLength()){uint32_tlength=argsobj->initialLength();MOZ_ASSERT(length<INT32_MAX);vp.setInt32(int32_t(length));returntrue;}}}returnfalse;}enumclassGetNameMode{Normal,TypeOf};template<GetNameModemode>inlineboolFetchName(JSContext*cx,HandleObjectreceiver,HandleObjectholder,HandlePropertyNamename,Handle<PropertyResult>prop,MutableHandleValuevp){if(!prop){switch(mode){caseGetNameMode::Normal:returnReportIsNotDefined(cx,name);caseGetNameMode::TypeOf:vp.setUndefined();returntrue;}}/* Take the slow path if shape was not found in a native object. */if(!receiver->isNative()||!holder->isNative()){Rooted<jsid>id(cx,NameToId(name));if(!GetProperty(cx,receiver,receiver,id,vp))returnfalse;}else{RootedShapeshape(cx,prop.shape());if(shape->isDataDescriptor()&&shape->hasDefaultGetter()){/* Fast path for Object instance properties. */MOZ_ASSERT(shape->hasSlot());vp.set(holder->as<NativeObject>().getSlot(shape->slot()));}else{// Unwrap 'with' environments for reasons given in// GetNameBoundInEnvironment.RootedObjectnormalized(cx,MaybeUnwrapWithEnvironment(receiver));if(!NativeGetExistingProperty(cx,normalized,holder.as<NativeObject>(),shape,vp))returnfalse;}}// We do our own explicit checking for |this|if(name==cx->names().dotThis)returntrue;// NAME operations are the slow paths already, so unconditionally check// for uninitialized lets.returnCheckUninitializedLexical(cx,name,vp);}inlineboolFetchNameNoGC(JSObject*pobj,PropertyResultprop,MutableHandleValuevp){if(!prop||!pobj->isNative())returnfalse;Shape*shape=prop.shape();if(!shape->isDataDescriptor()||!shape->hasDefaultGetter())returnfalse;vp.set(pobj->as<NativeObject>().getSlot(shape->slot()));return!IsUninitializedLexical(vp);}template<js::GetNameModemode>inlineboolGetEnvironmentName(JSContext*cx,HandleObjectenvChain,HandlePropertyNamename,MutableHandleValuevp){{PropertyResultprop;JSObject*obj=nullptr;JSObject*pobj=nullptr;if(LookupNameNoGC(cx,name,envChain,&obj,&pobj,&prop)){if(FetchNameNoGC(pobj,prop,vp))returntrue;}}Rooted<PropertyResult>prop(cx);RootedObjectobj(cx),pobj(cx);if(!LookupName(cx,name,envChain,&obj,&pobj,&prop))returnfalse;returnFetchName<mode>(cx,obj,pobj,name,prop,vp);}inlineboolHasOwnProperty(JSContext*cx,HandleValueval,HandleValueidValue,bool*result){// As an optimization, provide a fast path when rooting is not necessary and// we can safely retrieve the object's shape.jsidid;if(val.isObject()&&ValueToId<NoGC>(cx,idValue,&id)){JSObject*obj=&val.toObject();PropertyResultprop;if(obj->isNative()&&NativeLookupOwnProperty<NoGC>(cx,&obj->as<NativeObject>(),id,&prop)){*result=prop.isFound();returntrue;}}// Step 1.RootedIdkey(cx);if(!ToPropertyKey(cx,idValue,&key))returnfalse;// Step 2.RootedObjectobj(cx,ToObject(cx,val));if(!obj)returnfalse;// Step 3.returnHasOwnProperty(cx,obj,key,result);}inlineboolGetIntrinsicOperation(JSContext*cx,jsbytecode*pc,MutableHandleValuevp){RootedPropertyNamename(cx,cx->currentScript()->getName(pc));returnGlobalObject::getIntrinsicValue(cx,cx->global(),name,vp);}inlineboolSetIntrinsicOperation(JSContext*cx,JSScript*script,jsbytecode*pc,HandleValueval){RootedPropertyNamename(cx,script->getName(pc));returnGlobalObject::setIntrinsicValue(cx,cx->global(),name,val);}inlinevoidSetAliasedVarOperation(JSContext*cx,JSScript*script,jsbytecode*pc,EnvironmentObject&obj,EnvironmentCoordinateec,constValue&val,MaybeCheckTDZcheckTDZ){MOZ_ASSERT_IF(checkTDZ,!IsUninitializedLexical(obj.aliasedBinding(ec)));// Avoid computing the name if no type updates are needed, as this may be// expensive on scopes with large numbers of variables.PropertyName*name=obj.isSingleton()?EnvironmentCoordinateName(cx->caches().envCoordinateNameCache,script,pc):nullptr;obj.setAliasedBinding(cx,ec,name,val);}inlineboolSetNameOperation(JSContext*cx,JSScript*script,jsbytecode*pc,HandleObjectenv,HandleValueval){MOZ_ASSERT(*pc==JSOP_SETNAME||*pc==JSOP_STRICTSETNAME||*pc==JSOP_SETGNAME||*pc==JSOP_STRICTSETGNAME);MOZ_ASSERT_IF((*pc==JSOP_SETGNAME||*pc==JSOP_STRICTSETGNAME)&&!script->hasNonSyntacticScope(),env==cx->global()||env==&cx->global()->lexicalEnvironment()||env->is<RuntimeLexicalErrorObject>());boolstrict=*pc==JSOP_STRICTSETNAME||*pc==JSOP_STRICTSETGNAME;RootedPropertyNamename(cx,script->getName(pc));// In strict mode, assigning to an undeclared global variable is an// error. To detect this, we call NativeSetProperty directly and pass// Unqualified. It stores the error, if any, in |result|.boolok;ObjectOpResultresult;RootedIdid(cx,NameToId(name));RootedValuereceiver(cx,ObjectValue(*env));if(env->isUnqualifiedVarObj()){RootedNativeObjectvarobj(cx);if(env->is<DebugEnvironmentProxy>())varobj=&env->as<DebugEnvironmentProxy>().environment().as<NativeObject>();elsevarobj=&env->as<NativeObject>();MOZ_ASSERT(!varobj->getOpsSetProperty());ok=NativeSetProperty(cx,varobj,id,val,receiver,Unqualified,result);}else{ok=SetProperty(cx,env,id,val,receiver,result);}returnok&&result.checkStrictErrorOrWarning(cx,env,id,strict);}inlineboolDefLexicalOperation(JSContext*cx,Handle<LexicalEnvironmentObject*>lexicalEnv,HandleObjectvarObj,HandlePropertyNamename,unsignedattrs){// Redeclaration checks should have already been done.MOZ_ASSERT(CheckLexicalNameConflict(cx,lexicalEnv,varObj,name));RootedIdid(cx,NameToId(name));RootedValueuninitialized(cx,MagicValue(JS_UNINITIALIZED_LEXICAL));returnNativeDefineProperty(cx,lexicalEnv,id,uninitialized,nullptr,nullptr,attrs);}inlineboolDefLexicalOperation(JSContext*cx,LexicalEnvironmentObject*lexicalEnvArg,JSObject*varObjArg,JSScript*script,jsbytecode*pc){MOZ_ASSERT(*pc==JSOP_DEFLET||*pc==JSOP_DEFCONST);RootedPropertyNamename(cx,script->getName(pc));unsignedattrs=JSPROP_ENUMERATE|JSPROP_PERMANENT;if(*pc==JSOP_DEFCONST)attrs|=JSPROP_READONLY;Rooted<LexicalEnvironmentObject*>lexicalEnv(cx,lexicalEnvArg);RootedObjectvarObj(cx,varObjArg);MOZ_ASSERT_IF(!script->hasNonSyntacticScope(),lexicalEnv==&cx->global()->lexicalEnvironment()&&varObj==cx->global());returnDefLexicalOperation(cx,lexicalEnv,varObj,name,attrs);}inlinevoidInitGlobalLexicalOperation(JSContext*cx,LexicalEnvironmentObject*lexicalEnvArg,JSScript*script,jsbytecode*pc,HandleValuevalue){MOZ_ASSERT_IF(!script->hasNonSyntacticScope(),lexicalEnvArg==&cx->global()->lexicalEnvironment());MOZ_ASSERT(*pc==JSOP_INITGLEXICAL);Rooted<LexicalEnvironmentObject*>lexicalEnv(cx,lexicalEnvArg);RootedShapeshape(cx,lexicalEnv->lookup(cx,script->getName(pc)));MOZ_ASSERT(shape);lexicalEnv->setSlot(shape->slot(),value);}inlineboolInitPropertyOperation(JSContext*cx,JSOpop,HandleObjectobj,HandleIdid,HandleValuerhs){if(obj->is<PlainObject>()||obj->is<JSFunction>()){unsignedpropAttrs=GetInitDataPropAttrs(op);returnNativeDefineProperty(cx,obj.as<NativeObject>(),id,rhs,nullptr,nullptr,propAttrs);}MOZ_ASSERT(obj->as<UnboxedPlainObject>().layout().lookup(id));returnPutProperty(cx,obj,id,rhs,false);}inlineboolDefVarOperation(JSContext*cx,HandleObjectvarobj,HandlePropertyNamedn,unsignedattrs){MOZ_ASSERT(varobj->isQualifiedVarObj());#ifdef DEBUG// Per spec, it is an error to redeclare a lexical binding. This should// have already been checked.if(JS_HasExtensibleLexicalEnvironment(varobj)){Rooted<LexicalEnvironmentObject*>lexicalEnv(cx);lexicalEnv=&JS_ExtensibleLexicalEnvironment(varobj)->as<LexicalEnvironmentObject>();MOZ_ASSERT(CheckVarNameConflict(cx,lexicalEnv,dn));}#endifRooted<PropertyResult>prop(cx);RootedObjectobj2(cx);if(!LookupProperty(cx,varobj,dn,&obj2,&prop))returnfalse;/* Steps 8c, 8d. */if(!prop||(obj2!=varobj&&varobj->is<GlobalObject>())){if(!DefineProperty(cx,varobj,dn,UndefinedHandleValue,nullptr,nullptr,attrs))returnfalse;}if(varobj->is<GlobalObject>()){if(!varobj->compartment()->addToVarNames(cx,dn))returnfalse;}returntrue;}staticMOZ_ALWAYS_INLINEboolNegOperation(JSContext*cx,HandleScriptscript,jsbytecode*pc,HandleValueval,MutableHandleValueres){/* * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the * results, -0.0 or INT32_MAX + 1, are double values. */int32_ti;if(val.isInt32()&&(i=val.toInt32())!=0&&i!=INT32_MIN){res.setInt32(-i);}else{doubled;if(!ToNumber(cx,val,&d))returnfalse;res.setNumber(-d);}returntrue;}staticMOZ_ALWAYS_INLINEboolToIdOperation(JSContext*cx,HandleScriptscript,jsbytecode*pc,HandleValueidval,MutableHandleValueres){if(idval.isInt32()){res.set(idval);returntrue;}RootedIdid(cx);if(!ToPropertyKey(cx,idval,&id))returnfalse;res.set(IdToValue(id));returntrue;}staticMOZ_ALWAYS_INLINEboolGetObjectElementOperation(JSContext*cx,JSOpop,JS::HandleObjectobj,JS::HandleValuereceiver,HandleValuekey,MutableHandleValueres){MOZ_ASSERT(op==JSOP_GETELEM||op==JSOP_CALLELEM||op==JSOP_GETELEM_SUPER);MOZ_ASSERT_IF(op==JSOP_GETELEM||op==JSOP_CALLELEM,obj==&receiver.toObject());do{uint32_tindex;if(IsDefinitelyIndex(key,&index)){if(GetElementNoGC(cx,obj,receiver,index,res.address()))break;if(!GetElement(cx,obj,receiver,index,res))returnfalse;break;}if(key.isString()){JSString*str=key.toString();JSAtom*name=str->isAtom()?&str->asAtom():AtomizeString(cx,str);if(!name)returnfalse;if(name->isIndex(&index)){if(GetElementNoGC(cx,obj,receiver,index,res.address()))break;}else{if(GetPropertyNoGC(cx,obj,receiver,name->asPropertyName(),res.address()))break;}}RootedIdid(cx);if(!ToPropertyKey(cx,key,&id))returnfalse;if(!GetProperty(cx,obj,receiver,id,res))returnfalse;}while(false);assertSameCompartmentDebugOnly(cx,res);returntrue;}staticMOZ_ALWAYS_INLINEboolGetPrimitiveElementOperation(JSContext*cx,JSOpop,JS::HandleValuereceiver,HandleValuekey,MutableHandleValueres){MOZ_ASSERT(op==JSOP_GETELEM||op==JSOP_CALLELEM);// FIXME: Bug 1234324 We shouldn't be boxing here.RootedObjectboxed(cx,ToObjectFromStack(cx,receiver));if(!boxed)returnfalse;do{uint32_tindex;if(IsDefinitelyIndex(key,&index)){if(GetElementNoGC(cx,boxed,receiver,index,res.address()))break;if(!GetElement(cx,boxed,receiver,index,res))returnfalse;break;}if(key.isString()){JSString*str=key.toString();JSAtom*name=str->isAtom()?&str->asAtom():AtomizeString(cx,str);if(!name)returnfalse;if(name->isIndex(&index)){if(GetElementNoGC(cx,boxed,receiver,index,res.address()))break;}else{if(GetPropertyNoGC(cx,boxed,receiver,name->asPropertyName(),res.address()))break;}}RootedIdid(cx);if(!ToPropertyKey(cx,key,&id))returnfalse;if(!GetProperty(cx,boxed,receiver,id,res))returnfalse;}while(false);assertSameCompartmentDebugOnly(cx,res);returntrue;}staticMOZ_ALWAYS_INLINEboolGetElemOptimizedArguments(JSContext*cx,AbstractFramePtrframe,MutableHandleValuelref,HandleValuerref,MutableHandleValueres,bool*done){MOZ_ASSERT(!*done);if(IsOptimizedArguments(frame,lref)){if(rref.isInt32()){int32_ti=rref.toInt32();if(i>=0&&uint32_t(i)<frame.numActualArgs()){res.set(frame.unaliasedActual(i));*done=true;returntrue;}}RootedScriptscript(cx,frame.script());if(!JSScript::argumentsOptimizationFailed(cx,script))returnfalse;lref.set(ObjectValue(frame.argsObj()));}returntrue;}staticMOZ_ALWAYS_INLINEboolGetElementOperation(JSContext*cx,JSOpop,HandleValuelref,HandleValuerref,MutableHandleValueres){MOZ_ASSERT(op==JSOP_GETELEM||op==JSOP_CALLELEM);uint32_tindex;if(lref.isString()&&IsDefinitelyIndex(rref,&index)){JSString*str=lref.toString();if(index<str->length()){str=cx->staticStrings().getUnitStringForElement(cx,str,index);if(!str)returnfalse;res.setString(str);returntrue;}}if(lref.isPrimitive()){RootedValuethisv(cx,lref);returnGetPrimitiveElementOperation(cx,op,thisv,rref,res);}RootedObjectobj(cx,&lref.toObject());RootedValuethisv(cx,lref);returnGetObjectElementOperation(cx,op,obj,thisv,rref,res);}staticMOZ_ALWAYS_INLINEJSString*TypeOfOperation(constValue&v,JSRuntime*rt){JSTypetype=js::TypeOfValue(v);returnTypeName(type,*rt->commonNames);}staticMOZ_ALWAYS_INLINEboolInitElemOperation(JSContext*cx,jsbytecode*pc,HandleObjectobj,HandleValueidval,HandleValueval){MOZ_ASSERT(!val.isMagic(JS_ELEMENTS_HOLE));MOZ_ASSERT(!obj->getClass()->getGetProperty());MOZ_ASSERT(!obj->getClass()->getSetProperty());RootedIdid(cx);if(!ToPropertyKey(cx,idval,&id))returnfalse;unsignedflags=JSOp(*pc)==JSOP_INITHIDDENELEM?0:JSPROP_ENUMERATE;returnDefineProperty(cx,obj,id,val,nullptr,nullptr,flags);}staticMOZ_ALWAYS_INLINEboolInitArrayElemOperation(JSContext*cx,jsbytecode*pc,HandleObjectobj,uint32_tindex,HandleValueval){JSOpop=JSOp(*pc);MOZ_ASSERT(op==JSOP_INITELEM_ARRAY||op==JSOP_INITELEM_INC);MOZ_ASSERT(obj->is<ArrayObject>()||obj->is<UnboxedArrayObject>());if(op==JSOP_INITELEM_INC&&index==INT32_MAX){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_SPREAD_TOO_LARGE);returnfalse;}/* * If val is a hole, do not call DefineElement. * * Furthermore, if the current op is JSOP_INITELEM_INC, always call * SetLengthProperty even if it is not the last element initialiser, * because it may be followed by JSOP_SPREAD, which will not set the array * length if nothing is spread. * * Alternatively, if the current op is JSOP_INITELEM_ARRAY, the length will * have already been set by the earlier JSOP_NEWARRAY; JSOP_INITELEM_ARRAY * cannot follow JSOP_SPREAD. */if(val.isMagic(JS_ELEMENTS_HOLE)){if(op==JSOP_INITELEM_INC){if(!SetLengthProperty(cx,obj,index+1))returnfalse;}}else{if(!DefineElement(cx,obj,index,val,nullptr,nullptr,JSPROP_ENUMERATE))returnfalse;}returntrue;}#define RELATIONAL_OP(OP) \ JS_BEGIN_MACRO \/* Optimize for two int-tagged operands (typical loop control). */ \ if (lhs.isInt32() && rhs.isInt32()) { \ *res = lhs.toInt32() OP rhs.toInt32(); \ } else { \ if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) \ return false; \ if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) \ return false; \ if (lhs.isString() && rhs.isString()) { \ JSString* l = lhs.toString(); \ JSString* r = rhs.toString(); \ int32_t result; \ if (!CompareStrings(cx, l, r, &result)) \ return false; \ *res = result OP 0; \ } else { \ double l, r; \ if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r)) \ return false; \ *res = (l OP r); \ } \ } \ return true; \ JS_END_MACROstaticMOZ_ALWAYS_INLINEboolLessThanOperation(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){RELATIONAL_OP(<);}staticMOZ_ALWAYS_INLINEboolLessThanOrEqualOperation(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){RELATIONAL_OP(<=);}staticMOZ_ALWAYS_INLINEboolGreaterThanOperation(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){RELATIONAL_OP(>);}staticMOZ_ALWAYS_INLINEboolGreaterThanOrEqualOperation(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){RELATIONAL_OP(>=);}staticMOZ_ALWAYS_INLINEboolBitNot(JSContext*cx,HandleValuein,int*out){inti;if(!ToInt32(cx,in,&i))returnfalse;*out=~i;returntrue;}staticMOZ_ALWAYS_INLINEboolBitXor(JSContext*cx,HandleValuelhs,HandleValuerhs,int*out){intleft,right;if(!ToInt32(cx,lhs,&left)||!ToInt32(cx,rhs,&right))returnfalse;*out=left^right;returntrue;}staticMOZ_ALWAYS_INLINEboolBitOr(JSContext*cx,HandleValuelhs,HandleValuerhs,int*out){intleft,right;if(!ToInt32(cx,lhs,&left)||!ToInt32(cx,rhs,&right))returnfalse;*out=left|right;returntrue;}staticMOZ_ALWAYS_INLINEboolBitAnd(JSContext*cx,HandleValuelhs,HandleValuerhs,int*out){intleft,right;if(!ToInt32(cx,lhs,&left)||!ToInt32(cx,rhs,&right))returnfalse;*out=left&right;returntrue;}staticMOZ_ALWAYS_INLINEboolBitLsh(JSContext*cx,HandleValuelhs,HandleValuerhs,int*out){int32_tleft,right;if(!ToInt32(cx,lhs,&left)||!ToInt32(cx,rhs,&right))returnfalse;*out=uint32_t(left)<<(right&31);returntrue;}staticMOZ_ALWAYS_INLINEboolBitRsh(JSContext*cx,HandleValuelhs,HandleValuerhs,int*out){int32_tleft,right;if(!ToInt32(cx,lhs,&left)||!ToInt32(cx,rhs,&right))returnfalse;*out=left>>(right&31);returntrue;}staticMOZ_ALWAYS_INLINEboolUrshOperation(JSContext*cx,HandleValuelhs,HandleValuerhs,MutableHandleValueout){uint32_tleft;int32_tright;if(!ToUint32(cx,lhs,&left)||!ToInt32(cx,rhs,&right))returnfalse;left>>=right&31;out.setNumber(uint32_t(left));returntrue;}template<typenameT>staticMOZ_ALWAYS_INLINEboolSignExtendOperation(JSContext*cx,HandleValuein,int*out){int32_ti;if(!ToInt32(cx,in,&i))returnfalse;*out=(T)i;returntrue;}#undef RELATIONAL_OPinlineJSFunction*ReportIfNotFunction(JSContext*cx,HandleValuev,MaybeConstructconstruct=NO_CONSTRUCT){if(v.isObject()&&v.toObject().is<JSFunction>())return&v.toObject().as<JSFunction>();ReportIsNotFunction(cx,v,-1,construct);returnnullptr;}/* * FastCallGuard is used to optimize calls to JS functions from natives written * in C++, e.g. Array.prototype.map. If the callee is not Ion-compiled, this * will just call js::Call. If the callee has a valid IonScript, however, it * will enter Ion directly. */classFastCallGuard{InvokeArgsargs_;RootedFunctionfun_;RootedScriptscript_;// Constructing a JitContext is pretty expensive due to the TLS access,// so only do this if we have to.booluseIon_;public:FastCallGuard(JSContext*cx,constValue&fval):args_(cx),fun_(cx),script_(cx),useIon_(jit::IsIonEnabled(cx)){initFunction(fval);}voidinitFunction(constValue&fval){if(fval.isObject()&&fval.toObject().is<JSFunction>()){JSFunction*fun=&fval.toObject().as<JSFunction>();if(fun->isInterpreted())fun_=fun;}}InvokeArgs&args(){returnargs_;}boolcall(JSContext*cx,HandleValuecallee,HandleValuethisv,MutableHandleValuerval){args_.CallArgs::setCallee(callee);args_.CallArgs::setThis(thisv);if(useIon_&&fun_){if(!script_){script_=JSFunction::getOrCreateScript(cx,fun_);if(!script_)returnfalse;}MOZ_ASSERT(fun_->nonLazyScript()==script_);jit::MethodStatusstatus=jit::CanEnterUsingFastInvoke(cx,script_,args_.length());if(status==jit::Method_Error)returnfalse;if(status==jit::Method_Compiled){jit::JitExecStatusresult=jit::FastInvoke(cx,fun_,args_);if(IsErrorStatus(result))returnfalse;MOZ_ASSERT(result==jit::JitExec_Ok);rval.set(args_.CallArgs::rval());returntrue;}MOZ_ASSERT(status==jit::Method_Skipped);if(script_->canIonCompile()){// This script is not yet hot. Since calling into Ion is much// faster here, bump the warm-up counter a bit to account for this.script_->incWarmUpCounter(5);}}if(!InternalCallOrConstruct(cx,args_,NO_CONSTRUCT))returnfalse;rval.set(args_.CallArgs::rval());returntrue;}private:FastCallGuard(constFastCallGuard&other)=delete;voidoperator=(constFastCallGuard&other)=delete;};}/* namespace js */#endif /* vm_Interpreter_inl_h */